// Copyright (c) 2013, yuno. All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// 3. Neither the name of the copyright holder nor the names of contributors
//    may be used to endorse or promote products derived from this software
//    without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
package sugarmintcandy.widgetwindow;

import java.util.HashMap;
import java.util.Iterator;

import android.annotation.SuppressLint;
import android.appwidget.AppWidgetHost;
import android.content.Context;

@SuppressLint("UseSparseArrays")
public class MyAppWidgetHostManager {
    private Context mContext;
    private MainDatabase mDatabase;
    private HashMap<Integer, MyAppWidgetHost> mHosts;

    public MyAppWidgetHostManager(MainDatabase database) {
	mContext = database.getContext();
	mDatabase = database;
	mHosts = new HashMap<Integer, MyAppWidgetHost>();
	new AppWidgetHost(mContext, 0);
	if (database.getNumberOfWindows() == 0) {
	    AppWidgetHost.deleteAllHosts();
	}
    }

    public void stop() {
	Debug.trace();
	for (MyAppWidgetHost host : mHosts.values()) {
	    host.stopListening();
	    host.release();
	    Debug.trace("Host %d stops listening.", host.getHostId());
	}
	mHosts.clear();
    }

    private MyAppWidgetHost getHost(int hostId) {
	MyAppWidgetHost host = mHosts.get(hostId);
	if (host == null) {
	    host = new MyAppWidgetHost(mContext, hostId);
	    host.startListening();
	    mHosts.put(hostId, host);
	    Debug.trace("Host %d starts listening.", hostId);
	}
	return host;
    }

    public MyAppWidgetHostView getView(WindowInfo info) {
	MyAppWidgetHost host = getHost(info.hostId);
	return host.getView(mContext, info.appWidgetId, info.providerInfo);
    }

    public void releaseView(MyAppWidgetHostView view) {
	int hostId = view.getHostId();
	MyAppWidgetHost host = mHosts.get(hostId);
	if (host != null) {
	    host.releaseView(view);
	}
    }

    public void cleanHosts() {
	Iterator<MyAppWidgetHost> it = mHosts.values().iterator();
	while (it.hasNext()) {
	    MyAppWidgetHost host = it.next();
	    if (host.isEmpty()) {
		host.stopListening();
		host.release();
		it.remove();
		Debug.trace("Host %d stops listening.", host.getHostId());
	    }
	}
    }

    public int allocateAppWidgetId() {
	int hostId = mDatabase.getMaxHostId() + 1;
	int appWidgetId = getHost(hostId).allocateAppWidgetId();
	mDatabase.addAppWidgetId(appWidgetId, hostId);
	return appWidgetId;
    }

    public void deleteAppWidgetId(int appWidgetId) {
	deleteAppWidgetId(appWidgetId,
		mDatabase.getHostIdFromAppWidgetId(appWidgetId));
    }

    public void deleteAppWidgetId(int appWidgetId, int hostId) {
	MyAppWidgetHost host = mHosts.get(hostId);
	if (host == null) {
	    host = new MyAppWidgetHost(mContext, hostId);
	}
	host.deleteAppWidgetId(appWidgetId);
	mDatabase.deleteAppWidgetId(appWidgetId);
    }

    public void cleanAppWidgetIdLeaks() {
	HashMap<Integer, WindowInfo> usedIds = new HashMap<Integer, WindowInfo>();
	WindowInfo[] infoList = mDatabase.getWindowInfoList();
	for (WindowInfo info : infoList) {
	    usedIds.put(info.appWidgetId, info);
	}
	for (int id : mDatabase.getAppWidgetIds()) {
	    if (usedIds.remove(id) == null) {
		deleteAppWidgetId(id, mDatabase.getHostIdFromAppWidgetId(id));
	    }
	}
	for (WindowInfo info : usedIds.values()) {
	    mDatabase.addAppWidgetId(info.appWidgetId, info.hostId);
	}
    }
}
